<?php

namespace decrypt;

class DeckDecode
{

	private string $content;

	public function __construct()
	{
		$file_list = scan_files(ENCODE_ROOT);
		foreach ($file_list as $file) {
			output("开始解密 [$file]");
			$this->content = file_get_contents($file);
			// $this->content = (new GotoDecode($file))->decode();
			// if (empty($this->content)) {
			// 	output("GotoDecode 解密器解密 [$file] 失败！", 'error');
			// 	continue;
			// } else {
			// 	output("GotoDecode 解密器解密 [$file]");
			// }

			$this->decode();

			if (empty($this->content)) {
				output("DeckDecode 解密器解密 [$file] 失败！", 'error');
				continue;
			} else {
				output("DeckDecode 解密器解密 [$file]");
			}

			$file_path = str_replace(ENCODE_ROOT, DECODE_ROOT, $file);
			$file_dir = dirname($file_path);
			if (!is_dir($file_dir)) mkdir($file_dir, 0755, true);

			file_put_contents($file_path, $this->content);
		}
	}

	public function decode()
	{
		// 分离头部代码
		$this->separateTopBin();

		$this->content = str_replace("gzinflate(substr(base64_decode('H4sIAAAAAAAAAytITM4GACNe3pcEAAAA'), 10, -8))", "'pack'", $this->content);

		$this->content = str_replace("base64_decode(str_rot13('pTSwnj'))", "'pack'", $this->content);

		$this->content = str_replace("base64_decode('cGFjaw')", "'pack'", $this->content);

		// 解码 call_user_func 函数
		$this->decodeCallUserFunc();

		// 解码 $GLOBALS 数组访问
		$this->decodeGlobalsArrayAccess();

		$this->content = $this->strDecode('/\$_GET\[pack\(\$_GET\[.*?\]\[.*?\],\s?\$_GET\[.*?\]\[.*?\]\)\]/i', $this->content);
	
		// 解码 $_GET 数组访问
		$this->decodeGetsArrayAccess();

		// 解码 pack 函数
		$this->decodePackFunction();

		// 解密后的代码
		return $this->DecodeCode();
	}

	private function separateTopBin()
	{
		// $preg_split = preg_split('/unset\(\$\w+\);/ims', $this->content);
		$preg_split = preg_split('/error_reporting\(0\);/ims', $this->content);
		$topbin = $preg_split[0];
		file_put_contents('topbin.php', $topbin);
		include 'topbin.php';
		unset($preg_split[0]);
		$this->content = implode(PHP_EOL, $preg_split);
	}

	private function decodeCallUserFunc()
	{
		$pattern = '/call_user_func\("\\\x70\\\x61\\\x63\\\x6b",\s?\$GLOBALS\[.*?\]\[.*?\],\s?\$GLOBALS\[.*?\]\[.*?\]\)/i';
		$this->content = $this->strDecode($pattern, $this->content);
	}

	private function decodeGlobalsArrayAccess()
	{
		$this->content = $this->strDecode('/(\$GLOBALS\[.*?])\[.*?\]/i', $this->content);
	}

	private function decodeGetsArrayAccess()
	{
		$this->content = $this->strDecode('/(\$_GET\[.*?])\[.*?\]/i', $this->content);
	}

	private function decodePackFunction()
	{
		$this->content = $this->strDecode("/pack\('H\*',\s?'.*?'\)/i", $this->content);
	}

	private function DecodeCode()
	{
		$content = '<?php' . PHP_EOL . $this->content;
		$this->content = $content;
		return $content;
	}

	private function strDecode($pattern, $content)
	{
		preg_match_all($pattern, $content, $matches);
		foreach ($matches[0] as $value) {
			$rand = rand() . '.php';
			$code = "<?php \$str = $value;";
			file_put_contents($rand, $code);
			require $rand;
			unlink($rand);
			$str = '\'' . str_replace("'", "\'", $str) . '\'';
			$str = str_replace("\\\\'", "\'", $str);
			$content = str_replace($value, $str, $content);
		}
		return $content;
	}
}
